package com.dhp.bkOjjudgeservice.codesandbox.utils;

import com.dhp.bkOjjudgeservice.JudgeService;
import com.dhp.model.entity.QuestionSubmit;
import com.github.rholder.retry.Retryer;
import com.github.rholder.retry.RetryerBuilder;
import com.github.rholder.retry.StopStrategies;
import com.github.rholder.retry.WaitStrategies;
import com.google.common.base.Predicates;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

/**
 * 判题重试工具类
 */
@Component
@Slf4j
public class RetryUtil {
    @Autowired
    private JudgeService judgeService;

    @SneakyThrows
    public QuestionSubmit retryJudge(QuestionSubmit questionSubmit){
        // 创建相应的retry规则
        //定义重试机制
        Retryer<QuestionSubmit> retryer = RetryerBuilder.<QuestionSubmit>newBuilder()
                //retryIf 重试条件
                .retryIfException()
                .retryIfRuntimeException()
                .retryIfExceptionOfType(Exception.class)
                .retryIfException(Predicates.equalTo(new Exception()))
                //如果返回为""重试
                .retryIfResult(Predicates.equalTo(null))

                //等待策略：每次请求间隔1s
                //fixedWait 固定X秒后重试
                //noWait不等时间直接重试
                //incrementingWait 第一个参数为第一次重试时间，后面会通过设置间隔递增秒数重试
                //randomWait 随机等待设置范围内的时间重试
                .withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECONDS))

                //停止策略 : 尝试请求3次
                .withStopStrategy(StopStrategies.stopAfterAttempt(3))
                .build();

        //定义请求实现
        Callable<QuestionSubmit> callable = new Callable<QuestionSubmit>() {
            int times = 1;

            @Override
            public QuestionSubmit call() throws Exception {
                log.info("重试调用={}", times);
                times++;
                try {
                    QuestionSubmit res = judgeService.doJudge(questionSubmit);
                    return res;
                }catch (Exception e){
                    return null;
                }
            }
        };
        return retryer.call(callable);
    }
}
